#!/usr/bin/python2
ident = '$Id: binder_ui.py 117 2006-06-18 16:56:13Z trevor $'
import wx, wx.gizmos, pdb
import rex, common, images, re, icon_manager, binders
#from gcb_service 			import *
from xml.dom	 			import minidom

# Sort BY and Find By
BY_ID		= 0
BY_NAME		= 1
BY_KIND		= 2

BY_INS_ID	= 0
BY_INS_NAME = 1
BY_VAR_ID	= 2
BY_VAR_NAME = 3
BY_BIN_ID	= 4
BY_BIN_NAME = 5

# Menu bar items
ID_SORTBY			= 101
ID_FINDBY			= 102
ID_FINDBY_TEXT		= 103

ID_RELOAD			= 104

ID_BIN_CREATE		= 111
ID_BIN_EDIT			= 112
ID_BIN_DELETE		= 113
ID_BIN_NEW_OPT		= 114
ID_BIN_NEW_VAR		= 115
ID_BIN_NEW_INS		= 116
ID_BIN_CLONE		= 117
ID_BIN_MIRROR		= 118
ID_BIN_COPY			= 119

ID_INS_EDIT			= 121
ID_INS_DELETE		= 122
ID_INS_PREVIEW		= 123
ID_INS_CLONE		= 124
ID_INS_COPY			= 125
ID_INS_PASTE		= 126

ID_VAR_EDIT			= 131
ID_VAR_DELETE		= 132
ID_VAR_COPY			= 133

ID_OPT_DELETE		= 141

ID_GCB_SHOW			= 151

class binder_tree( wx.gizmos.TreeListCtrl ):
	def __init__( self, parent, id=-1 , style=0 ):
		wx.gizmos.TreeListCtrl.__init__( self, parent, id , style=style)
		self.sortby = BY_NAME
		self.ascending = 1
		if wx.Platform == '__WXMAC__':
			font = self.GetMainWindow().GetFont()
			font.SetPointSize( 10 )
			self.GetMainWindow().SetFont( font )
			font = self.GetHeaderWindow().GetFont()
			font.SetPointSize( 10 )
			self.GetHeaderWindow().SetFont( font )
			self.GetHeaderWindow().Refresh()

	def OnCompareItems( self, item1, item2 ):
		ascending = self.ascending
		t1 = self.GetPyData( item1 )
		t2 = self.GetPyData( item2 )
		v1 = ''
		v2 = ''
		if ( ( type( t1 ) == str ) or ( type( t1 ) == unicode ) ) and  ( t1 == 'Optimizations' ):
			return -1
		elif ( ( type( t2 ) == str ) or ( type( t2 ) == unicode ) ) and  ( t2 == 'Optimizations' ):
			return 1
		if isinstance( t1 , wx._controls.TreeItemId ):
			common.dprint(" ----------------- t1 is treeitemid" )
			return 0
		if isinstance( t2 , wx._controls.TreeItemId ):
			common.dprint(" ----------------- t2 is treeitemid" )
			return 0
		if ( t1 is None ) or ( t2 is None ): return 0
		# optimizations?
		if isinstance( t1 , rex.binders.optimization ) and isinstance( t2 , rex.binders.optimization ):
			if ( t1['unique'] == '1' ) and ( t2['unique'] == '0' ):
				return -1
			if ( t1['unique'] == '0' ) and ( t2['unique'] == '1' ):
				return 1
			if t1['variables'] > t2['variables'] :
				return 1
			if t1['variables'] < t2['variables'] :
				return -1
			return 0
		# Comparing binders ?
		if isinstance( t1 , rex.binders.binder ) and isinstance( t2 , rex.binders.binder ) and ( t1['kind'] != t2['kind'] or t1.mirror != t2.mirror ):
			# binders
			# system binders always on top, then mirrors
			v1 = self.get_kind_weight( t1 )
			v2 = self.get_kind_weight( t2 )
			# for kind sorting, always ascending
			ascending = 1
		elif self.sortby == BY_NAME:
			# variables are always ascending
			if isinstance( t1 , rex.binders.variable ) and isinstance( t2 , rex.binders.variable ): ascending = 1
			v1 = t1["name"].lower()
			v2 = t2["name"].lower()
		elif ( not isinstance( t1 , rex.binders.variable ) and not isinstance( t2 , rex.binders.variable ) ) and self.sortby == BY_ID:
			v1 = int( t1["id"] )
			v2 = int( t2["id"] )
		else:
			# this should never execute
			v1 = t1["name"].lower()
			v2 = t2["name"].lower()
		if v1 < v2:  return ( -1 * ascending )
		if v1 == v2: return 0
		return ( 1 * ascending )

	def get_kind_weight( self, t ):
		try: kind = t['kind']
		except: kind = ""
		try: mirror = t.mirror
		except: mirror = False
		if kind == "SYSTEM":
			return 1
		elif mirror:
			return 2
		else:
			return 3

class var_edit( wx.Dialog ):
	def __init__( 
			self, parent, ID, title, pos=wx.DefaultPosition,
			size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE ):
		pre = wx.PreDialog()
		pre.Create( parent, ID, title, pos, size, style )
		self.this = pre.this
		self.nameText = wx.TextCtrl( self, -1, "", size=(200,-1) )
		self.typeList  = ['number', 'shorttext', 'longtext', 'unlimited', 'timestamp']
		self.typeChoice = wx.Choice( self, 40, (80,50), choices=self.typeList )

	def ShowModal( self ):
		sizer = wx.BoxSizer( wx.VERTICAL )

		grid = wx.FlexGridSizer( cols=2, hgap=5, vgap=5 )
		nameLabel = wx.StaticText( self, -1, "name: " )
		typeLabel = wx.StaticText( self, -1, "type: " )
		grid.AddMany( [nameLabel, self.nameText, typeLabel, self.typeChoice,] )
		
		sizer.AddSizer( grid, 0, 
			wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5 )

		box = wx.BoxSizer( wx.HORIZONTAL )
		btn = wx.Button( self, wx.ID_OK, " OK" )
		box.Add( btn, 0, wx.ALIGN_CENTRE | wx.ALL, 5 )
		btn = wx.Button( self, wx.ID_CANCEL, " Cancel" )
		btn.SetDefault()
		box.Add( btn, 0, wx.ALIGN_CENTRE | wx.ALL, 5 )
		sizer.AddSizer( box, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5 )

		self.SetSizer( sizer )
		self.SetAutoLayout( True )
		sizer.Fit( self )

		return wx.Dialog.ShowModal( self )

class new_optimization( wx.Dialog ):
	# parent is assumed to be of type binder_control
	def __init__( 
			self, parent, ID, title, pos=wx.DefaultPosition,
			size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE ):

		# prepare Modal support
		pre = wx.PreDialog()
		pre.Create( parent, ID, title, pos, size, style )
		self.this = pre.this
		self.parent = parent
		common.metalic( self )
		# see if we should quit early
		item = self.parent.tree.GetSelection()
		if item is None: return
		self.bin = self.parent.tree.GetPyData( item )
		if self.bin is None: return
		if self.bin.object_name != "binder": return
		if self.bin.mirror: return
		if ( self.bin["kind"] == "SYSTEM" ) and ( self.bin["name"] != "CONTACT" ): return

		# get optimization specific data
		self.opt = rex.binders.optimization( self.parent.account, self.bin, None )
		self.vars = [ var['name'].lower() for var in self.bin.variables ]

		# build some ui components
		self.lb1 = wx.ListBox( self, -1, wx.DefaultPosition, wx.Size( 150, 200 ), self.vars, wx.LB_EXTENDED | wx.LB_SORT )
		self.lb2 = wx.CheckListBox( self, -1, wx.DefaultPosition, wx.Size( 150, 200 ), [], wx.LB_SINGLE )
		self.removeButton   = wx.Button( self, -1, "<", wx.DefaultPosition, wx.Size( 40, 40 ) )
		self.okButton = wx.Button( self, wx.ID_OK, " Create Optimization" )

		self.ShowModal()

	def __OnAdd( self, event ):
		for index in list( self.lb1.GetSelections() ):
			s = self.lb1.GetString( index )
			if s != "":
				self.lb2.Append( s )
				self.lb1.Delete( index )
		if self.lb2.GetCount() > 0:
			self.okButton.Enable( True )
			self.removeButton.Enable( True )

	def __OnRemove( self, event ):
		for index in list( self.lb2.GetSelections() ):
			s = self.lb2.GetString( index )
			if s != "":
				self.lb1.Append( s )
				self.lb2.Delete( index )
		if self.lb2.GetCount() <= 0:
			self.okButton.Enable( False )
			self.removeButton.Enable( False )

	def ShowModal( self ):
		key = 'CTRL'
		if wx.Platform == '__WXMAC__': key = 'APPLE'

		addButton   = wx.Button( self, -1, ">", wx.DefaultPosition, wx.Size( 40, 40 ) )
		addButton.Bind( wx.EVT_BUTTON, self.__OnAdd )
		self.removeButton.Bind( wx.EVT_BUTTON, self.__OnRemove )
		self.removeButton.Enable( False )
		#plusButton  = wx.Button( self, -1, "+", wx.DefaultPosition, wx.Size( 40, 40 ) )
		#minusButton = wx.Button( self, -1, "-", wx.DefaultPosition, wx.Size( 40, 40 ) )
		#pmSizer = wx.BoxSizer( wx.VERTICAL )
		#pmSizer.Add( plusButton, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5 )
		#pmSizer.Add( minusButton, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5 )

		outerSizer = wx.BoxSizer( wx.VERTICAL )
		unique_checkbox = wx.CheckBox( self, -1, "Unique" )

		sizer  = wx.BoxSizer( wx.HORIZONTAL )
		sizer.Add( self.lb1, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5 )
		sizer.Add( addButton, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5 )
		sizer.Add( self.removeButton, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5 )
		sizer.Add( self.lb2, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5 )
		#sizer.AddSizer( pmSizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5 )
		outerSizer.Add( unique_checkbox, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5 )
		outerSizer.AddSizer( sizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5 )

		box = wx.BoxSizer( wx.HORIZONTAL )
		self.okButton.Enable( False )
		box.Add( self.okButton, 0, wx.ALIGN_CENTRE | wx.ALL, 5 )
		btn = wx.Button( self, wx.ID_CANCEL, " Nevermind" )
		btn.SetDefault()
		box.Add( btn, 0, wx.ALIGN_CENTRE | wx.ALL, 5 )
		outerSizer.AddSizer( box, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5 )

		self.SetSizer( outerSizer )
		self.SetAutoLayout( True )
		outerSizer.Fit( self )

		res = wx.Dialog.ShowModal( self )
		if res != wx.ID_OK:
			self.opt = None
			return

		unique = unique_checkbox.IsChecked()
		variables = [ self.lb2.GetString( i ) for i in range( self.lb2.GetCount() ) ]
		checked   = [ str( self.lb2.IsChecked( i ) ) for i in range( self.lb2.GetCount() ) ]
		common.dprint( variables )
		self.opt['variables']= ','.join( variables )
		self.opt['directions']= ','.join( checked )
		if unique:
			self.opt['unique']	= '1'
		else:
			self.opt['unique']	= '0'
		# create
		if self.opt.create():
			self.parent.AppendOptimization( self.bin.otree_item, self.opt )
			self.parent.tree.SortChildren( self.bin.otree_item )

#		dlg = wx.MultiChoiceDialog( self.parent, "Select the variables you want to optimize, you may use the %s key to select multiples." % key,
#										"Choose Optimization Variables",
#										vars )


class binder_control( wx.Panel ):
	def __init__( self, parent, id, account ):
		wx.Panel.__init__( self, parent, id )
		self.ref_count 			= 1
		self.account 			= account
		self.account.window.binder_control = self
		self.last_objects_found	= []
		self.mirrors 			= []
		self.contact_variables	= []	# used by the contacts control to show a drop down with the variables for searching
		self.gcb_frame  		= None
		# Take care of the status bar and the menu bar
		#self.CreateStatusBar()
		# Create the menu bar
		self.create_menu_items()
		# Create the list control and set it's image list
		tID = wx.NewId()
		style = wx.TR_HAS_BUTTONS | wx.TR_NO_LINES | wx.TR_HIDE_ROOT | wx.TR_FULL_ROW_HIGHLIGHT
		if wx.Platform == '__WXMSW__':
			style = wx.TR_HAS_BUTTONS  | wx.TR_LINES_AT_ROOT | wx.TR_HIDE_ROOT | wx.TR_FULL_ROW_HIGHLIGHT
		self.tree = binder_tree( self, tID, style=style )
		self.tree.AddColumn( "id" )
		self.tree.AddColumn( "name" )
		self.tree.SetMainColumn(0)
		self.il = wx.ImageList( 16,16 )
		self.binder_icon = self.il.Add( images.getBinderBitmap() )
		self.variable_icon = self.il.Add( images.getVariableBitmap() )
		self.optimization_icon = self.il.Add( images.getOptimizationBitmap() )
		self.unique_optimization_icon = self.il.Add( images.getUniqueOptimizationBitmap() )
		self.instance_icon = self.il.Add( images.getInstanceBitmap() )
		self.mirror_binder_icon = self.il.Add( images.getMirrorBinderBitmap() )
		self.system_binder_icon = self.il.Add( images.getSystemBinderBitmap() )
		self.tree.SetImageList( self.il )
		self.tree.SetColumnWidth( 0, 80 )
		self.tree.SetColumnWidth( 1, 400 )
		self.default_fore_colour = self.tree.GetForegroundColour()
		self.default_back_colour = self.tree.GetBackgroundColour()
		#self.tree.SetToolTip( wxToolTip("Account Binders") )
		self.tree.GetMainWindow().Bind( wx.EVT_LEFT_DCLICK, self.OnItemDoubleClick )
		self.tree.GetMainWindow().Bind( wx.EVT_RIGHT_DOWN, self.OnTreeRightClick )
		self.tree.GetMainWindow().Bind( wx.EVT_LEFT_DOWN, self.OnTreeLeftClick )
		self.tree.GetHeaderWindow().Bind( wx.EVT_LEFT_DOWN, self.OnTreeHeaderLeftClick )
		#if wx.Platform != '__WXMAC__':
		self.tree.Bind( wx.EVT_TREE_BEGIN_DRAG, self.OnBeginDrag, id=tID )
		self.topbar = wx.BoxSizer( wx.HORIZONTAL )
		# The new button
		self.new_button = wx.BitmapButton( self, -1, images.getNewBinderBitmap(), size=common.button_size, style=wx.NO_BORDER )
		self.new_button.Bind( wx.EVT_BUTTON, self.OnBinderCreate )
		self.topbar.Add( self.new_button, 0 )
		# The refresh button
		self.refresh_button = wx.BitmapButton( self, -1, images.getRefreshBitmap(), size=common.button_size, style=wx.NO_BORDER )
		self.refresh_button.Bind( wx.EVT_BUTTON, self.reload_binders )
		self.topbar.Add( self.refresh_button, 0 )
		# The sorting selector
		#self.sortby_choice = wx.Choice( self, ID_SORTBY, choices=["ID", "Name", "Kind"] )
		#self.sortby_choice.SetSelection( 0 )
		#self.Bind( wx.EVT_CHOICE, self.OnSortByChange, id=ID_SORTBY )
		#self.topbar.Add( self.sortby_choice, 2, wx.EXPAND )
		self.topbar.Add( (3,3), 0, wx.EXPAND )
		# The finding selector
		self.findby_choice = wx.Choice( self, ID_FINDBY, choices=["Binder ID", "Binder Name"] )
		self.findby_choice.SetSelection( 0 )
		self.Bind( wx.EVT_CHOICE, self.OnFindByChange, id=ID_FINDBY )
		self.topbar.Add( self.findby_choice, 2, wx.EXPAND )
		self.find_by = 1	# Find by ID by default
		# The find text box
		self.find_text = wx.TextCtrl( self, ID_FINDBY_TEXT, "" )
		self.topbar.Add( self.find_text, 2, wx.EXPAND )
		self.Bind( wx.EVT_TEXT, self.OnFindByTextChange, id=ID_FINDBY_TEXT )
		self.find_text.Bind( wx.EVT_LEFT_DOWN, self.OnFindByTextClick )
		self.find_text.Bind( wx.EVT_KEY_DOWN, self.OnFindByTextKeyPress )
		# zoom button
		self.zoom_button = wx.BitmapButton( self, -1, images.getZoomBitmap(), size=common.button_size, style=wx.NO_BORDER )
		self.zoom_button.Bind( wx.EVT_BUTTON, self.OnZoom )
		self.topbar.Add( self.zoom_button, 0 )
		# The whole mess
		self.sizer = wx.BoxSizer( wx.VERTICAL )
		self.sizer.Add( self.topbar, 0, wx.EXPAND )
		self.sizer.Add( self.tree, 1, wx.EXPAND )
		self.SetSizer( self.sizer )
		self.SetAutoLayout( 1 )
		# Windows needs this call
		self.Layout()
		self.Show()
		self.binders = []
		self.reload_binders()

	def OnTreeHeaderLeftClick( self, event ):
		treeitem, thing, column_index = self.tree.HitTest( event.GetPositionTuple() )
		# flip the asc desc?
		if self.tree.sortby == column_index:
			self.tree.ascending = self.tree.ascending * -1
		self.tree.sortby = column_index
		self.tree.SortChildren( self.root )

	def OnTreeLeftClick( self, event ):
		self.tree.Refresh()
		event.Skip()

	def OnZoom( self, event ):
		if self.account.window: self.account.window.OnZoom( 3 )

	def OnBeginDrag( self, event ):
		item = self.tree.GetSelection()
		if item is None: return
		obj = self.tree.GetPyData( item )
		if obj is None: return
		#data = wxCustomDataObject( wxDataFormat( wxDF_TEXT ) )
		data = wx.PyTextDataObject()
		try:
			if  obj.object_name == "variable":
				if obj.binder["kind"] == "SYSTEM" or obj.binder.mirror:
					linktag = "<#[%s.%s]#>" % ( obj.binder["name"], obj["name"] )
				else:
					linktag = "<#[%s.%s]#>" % ( obj.binder["id"], obj["name"] )
				data.SetText( linktag )
			elif  obj.object_name == "variable_mirror":
				linktag = "<#[%s.%s]#>" % ( obj.binder.mirror_name, obj["name"] )
				data.SetText( linktag )
			elif obj.object_name == "binder":
				bintag = "%s.%s" % ( obj["name"], obj["id"] )
				data.SetText( bintag )
			else:
				return
		except:
			common.show_error( "Failed to initiate object drag and drop" )
		ds = wx.DropSource( self )
		ds.SetData( data )
		result = ds.DoDragDrop()	

	def create_menu_items( self ):
		# Create the menu bar
		#menubar = wx.MenuBar()
		# The service menu
		menu = wx.Menu()
		menu.Append( ID_RELOAD, "&Reload\tCtrl+R", " Reload this service" )
		self.Bind( wx.EVT_MENU, self.reload_binders, id=ID_RELOAD )
		menu.AppendSeparator()
		#menubar.Append( menu, "&Service" )
		# The binder menu
		#menu = wx.Menu()
		menu.Append( ID_BIN_CREATE, "&Create a New Binder", " Create a new binder" )
		menu.Append( ID_BIN_MIRROR, "&Mirror", " Mirror the selected binder" )
		menu.Append( ID_BIN_CLONE, "C&lone", " Clone the selected binder" )
		menu.AppendSeparator()
		menu.Append( ID_BIN_COPY, "Copy", " Copy the selected binder to the clipboard" )
		menu.Append( ID_BIN_EDIT, "&Edit", " Edit the selected binder" )
		menu.Append( ID_BIN_DELETE, "&Delete", " Delete the selected binder" )
		menu.AppendSeparator()
		menu.Append( ID_BIN_NEW_OPT, "Add New &Optimization", " Create a new optimization for the selected binder" )
		menu.Append( ID_BIN_NEW_VAR, "Add New &Variable", " Create a new variable in the selected binder" )
		#menu.Append( ID_BIN_NEW_INS, "Add New &Instance", " Create a new instance of the selected binder" )
		self.bin_menu = menu
		self.Bind( wx.EVT_MENU, self.OnBinderCreate, id=ID_BIN_CREATE )
		self.Bind( wx.EVT_MENU, self.OnBinderMirror, id=ID_BIN_MIRROR )
		self.Bind( wx.EVT_MENU, self.OnBinderClone, id=ID_BIN_CLONE )
		self.Bind( wx.EVT_MENU, self.OnBinderCopy, id=ID_BIN_COPY )
		self.Bind( wx.EVT_MENU, self.OnBinderEdit, id=ID_BIN_EDIT )
		self.Bind( wx.EVT_MENU, self.OnBinderDelete, id=ID_BIN_DELETE )
		self.Bind( wx.EVT_MENU, self.OnBinderNewOptimization, id=ID_BIN_NEW_OPT )
		self.Bind( wx.EVT_MENU, self.OnBinderNewVariable, id=ID_BIN_NEW_VAR )
		#self.Bind( wx.EVT_MENU, self.OnBinderNewInstance, id=ID_BIN_NEW_INS )
		#menubar.Append( menu, "&Binder" )
		# The instances/variables/opt node menu
		menu = wx.Menu()
		menu.Append( ID_BIN_NEW_OPT, "&Add New Optimization", " Create a new optimization for the selected binder" )
		self.opt_node_menu = menu
		menu = wx.Menu()
		menu.Append( ID_BIN_NEW_VAR, "&Add New Variable", " Create a new variable in the selected binder" )
		self.var_node_menu = menu
		menu = wx.Menu()
		menu.Append( ID_BIN_NEW_INS, "&Add New Instance", " Create a new instance of the selected binder" )
		self.ins_node_menu = menu
		# The opt menu
		menu = wx.Menu()
		menu.Append( ID_OPT_DELETE, "&Delete", " Delete the selected optimization" )
		self.Bind( wx.EVT_MENU, self.OnOptimizationDelete, id=ID_OPT_DELETE )
		self.opt_menu = menu
		# The variable menu
		menu = wx.Menu()
		menu.Append( ID_VAR_COPY, "&Copy", " Copy the selected variable to the clipboard" )
		menu.Append( ID_VAR_EDIT, "&Edit", " Edit the selected variable" )
		menu.Append( ID_VAR_DELETE, "&Delete", " Delete the selected variable" )
		self.Bind( wx.EVT_MENU, self.OnVariableCopy, id=ID_VAR_COPY )
		self.Bind( wx.EVT_MENU, self.OnVariableEdit, id=ID_VAR_EDIT )
		self.Bind( wx.EVT_MENU, self.OnVariableDelete, id=ID_VAR_DELETE )
		self.var_menu = menu
		# The gcb menu
		menu = wx.Menu()
		menu.Append( ID_GCB_SHOW, "&Group Combo Binders", " Show the GCB window" )
		self.Bind( wx.EVT_MENU, self.OnShowGCB, id=ID_GCB_SHOW)
		self.gcb_menu = menu
		#menubar.Append( menu, "&GCBs" )
		# All done
		#self.SetMenuBar( menubar )

	def ColorizeBinder( self, bin, bin_item ):
		# Colorize
		if bin["kind"] == "SYSTEM":
			bgcolor= common.sui_colors("ivory")
			color =  common.sui_colors("sandybrown")
			self.tree.SetItemTextColour( bin_item, color )
			self.tree.SetItemBackgroundColour( bin_item, bgcolor )
		elif bin.mirror:
			bgcolor= common.sui_colors("lightcyan1")
			color =  common.sui_colors("cyan4")
			self.tree.SetItemTextColour( bin_item, color )
			self.tree.SetItemBackgroundColour( bin_item, bgcolor )
		else:
			self.tree.SetItemTextColour( bin_item, self.default_fore_colour )
			self.tree.SetItemBackgroundColour( bin_item, self.default_back_colour )

	def AppendBinder( self, bin ):
		# Colorize
		if bin["kind"] == "SYSTEM":
			bin_name = u"%s (system)" % bin["name"]
			bin.tree_item = self.tree.AppendItem( self.root, ' ' )
			self.tree.SetItemText( bin.tree_item, bin_name, 1 )
			self.tree.SetItemImage( bin.tree_item, self.system_binder_icon )
			if bin["name"] == 'CONTACT':
				# add the optimizations node
				bin.otree_item = self.tree.AppendItem( bin.tree_item, ' ' )
				self.tree.SetItemText( bin.otree_item, 'Optimizations', 1 )
				self.tree.SetPyData( bin.otree_item, 'Optimizations' )
				self.tree.SetItemImage( bin.otree_item, self.unique_optimization_icon )
		elif bin.mirror:
			bin_name = u"%s (mirror of %s)" % ( bin['name'], bin.original_name )
			bin.tree_item = self.tree.AppendItem( self.root, ' ' )
			self.tree.SetItemText( bin.tree_item, bin_name, 1 )
			self.tree.SetItemImage( bin.tree_item, self.mirror_binder_icon )
			self.mirrors.append( bin )
		else:
			bin.tree_item = self.tree.AppendItem( self.root, bin["id"] )
			self.tree.SetItemText( bin.tree_item, bin["name"], 1 )
			self.tree.SetItemImage( bin.tree_item, self.binder_icon )
			# add the optimizations node
			bin.otree_item = self.tree.AppendItem( bin.tree_item, ' ' )
			self.tree.SetItemText( bin.otree_item, 'Optimizations', 1 )
			self.tree.SetPyData( bin.otree_item, 'Optimizations' )
			self.tree.SetItemImage( bin.otree_item, self.unique_optimization_icon )
		self.ColorizeBinder( bin, bin.tree_item )
		self.tree.SetItemBold( bin.tree_item, 1 )
		# Now, cross link
		self.tree.SetPyData( bin.tree_item, bin )
		return bin.tree_item
		
	def AppendOptimization( self, obin_item, opt ):
		opt_item = self.tree.AppendItem( obin_item, ' ' )
		label = ''
		if opt['unique'] == '1':
			label = 'Unique ' + opt["variables"]
			self.tree.SetItemTextColour( opt_item, common.sui_colors("darkgreen") )
			self.tree.SetItemImage( opt_item, self.unique_optimization_icon, 1 )
			self.tree.SetItemBold( opt_item, 1 )
		else:
			label = opt["variables"]
			self.tree.SetItemTextColour( opt_item, common.sui_colors("darkolivegreen") )
			self.tree.SetItemImage( opt_item, self.optimization_icon, 1 )
		self.tree.SetItemText( opt_item, label, 1 )
		
		
		
		# Now, cross link
		self.tree.SetPyData( opt_item, opt )
		return opt_item
		
	def AppendVariable( self, bin_item, var ):
		var_item = self.tree.AppendItem( bin_item, ' ' )
		self.tree.SetItemText( var_item, var["name"], 1 )
		self.tree.SetItemImage( var_item, self.variable_icon, 1 )
		# Now, cross link
		self.tree.SetItemTextColour( var_item, common.sui_colors("indianred4") )
		self.tree.SetPyData( var_item, var )
		return var_item

	def reload_binders( self, event=None ):
		# Close off all open child frames
		if not self.CloseAllFrames(): return
		if self.account.window: self.account.window.SetStatusText( "Getting Binders..." )
		wx.Yield()
		# Clear out the current tree
		self.binders = []
		self.mirrors = []
		self.tree.DeleteAllItems()
		wx.Yield()
		# Add the root
		self.root = self.tree.AddRoot("Binders")
		#self.tree.SetPyData( self.root, None )
		# Get the binders
		cur = wx.BusyCursor()
		bins = None
		#try:
		xmlstring = self.account.execute('base', "binders_get2")
		#try:
		xmlstring = common.uni2str( xmlstring )
		pdom 	= minidom.parseString( xmlstring )
		bins	= pdom.firstChild
		#except:
		del cur
		if not bins:
			common.dprint( "unable to convert xmlstring" )
			return
		for pnode in bins.getElementsByTagName("binder"):
			# we send the xml, the service connector, and the ui so the binder class can access the
			# binders list when creating mirror binders.
			# we pass in the binders array so it can check for mirrors
			common.dprint( "pnode's type is %s" % ( type( pnode ) ) )
			common.dprint( "pnode has attributes:" )
			for attrib in pnode.attributes.items():
				k, v = attrib
				common.dprint( "     %s => %s" % (k , v) )
			common.dprint( "Parsing %s \n" % ( pnode.toxml() ) )
			bin = rex.binders.binder( self.account, pnode.toxml() )
			common.dprint("Loaded binder variables ", bin.variables)
			self.binders.append( bin )
			# Create a tree node for the binder object and it's children
			bin_item = self.AppendBinder( bin )
			bin.tree_item = bin_item
			# It's optimizations
			if bin.otree_item:
				for opt in bin.optimizations:
					opt_item = self.AppendOptimization( bin.otree_item, opt )
					opt.tree_item = opt_item
				self.tree.SortChildren( bin.otree_item )
			# It's variables
			for var in bin.variables:
				var_item = self.AppendVariable( bin.tree_item, var )
				var.tree_item = var_item
				if bin['kind'] == 'SYSTEM' and bin['name'] == 'CONTACT':
					self.contact_variables.append( var['name'].lower() )
			self.contact_variables.sort()
			self.tree.SortChildren( bin.tree_item )
		self.tree.SortChildren( self.root )
		try:
			self.tree.Expand( self.root )
		except:
			pass
		self.rebuild_mirrors()
		if self.account.window: self.account.window.SetStatusText( "Ready" )
		self.tree.Refresh()

	def rebuild_mirrors( self, bin = None ):
		if bin is None:
			binders = self.binders
		else:
			binders = [bin]
		for b in binders:
			# Find all mirros of this binder
			mirrors = self.get_mirrors_of_binder( b )
			if len( mirrors ) < 1: continue
			# Update their variables node
			for m in mirrors:
				self.update_mirror_from_binder( m, b )

	def get_mirrors_of_binder( self, bin ):
		mirrors = []
		if bin is None: return mirrors
		for m in self.mirrors:
			if bin['id'] == m['mirror_id']:
				mirrors.append( m )
		return mirrors

	def update_mirror_from_binder( self, mir, bin ):
		if mir is None: return
		if bin is None: return
		mvn = mir.tree_item
		bvn = bin.tree_item
		# Remove all the old variables and instances and their tree items
		mir.variables = []
		#~ mir.instances = []
		self.tree.DeleteChildren( mvn )
		# For each real variable, create a copy
		for v in bin.variables:
			# mark the variable name as dirty so it would come back from toxml()
			common.dprint("umfb: v", v)
			common.dprint("umfb: v.data", v.data)
			v.data[1]['dirty'] = True
			newv = rex.binders.variable( bin.account, mir, v.toxml() )
			v.data[1]['dirty'] = False
			newv["binder_id"] = "0"
			newv.object_name  = "variable_mirror"
			# Add it to the mirror
			mir.variables.append( newv )
			# Add it to the tree node
			self.AppendVariable( mvn, newv )

	def OnShowGCB( self, event ):
		if self.gcb_frame is not None: return
		self.gcb_frame = gcb_service( self, -1, "Group Combo Binders", self.account )

	def OnSortByChange( self, event ):
		self.last_objects_found	= []
		selected = self.sortby_choice.GetSelection()
		if selected < 0: return
		if self.root is None: return
		if self.tree.GetChildrenCount( self.root ) < 1: return
		# Sort the root
		self.tree.sortby = selected
		self.tree.SortChildren( self.root )
		# Now sort all the binder instances
		for bin in self.binders:
			if bin.tree_item is not None: self.tree.SortChildren( bin.tree_item )

	def OnFindByChange( self, event ):
		selected = self.findby_choice.GetSelection()
		if selected < 0: return
		if self.root is None: return
		if self.tree.GetChildrenCount( self.root ) < 1: return
		self.find_text.SetValue("")
		self.find_text.SetFocus()

	def OnFindByTextClick( self, event ):
		length = len( self.find_text.GetValue() )
		if length > 0:
			self.find_text.SetSelection( 0, length )
		event.Skip()

	def OnFindByTextKeyPress( self, event ):
		if event.GetKeyCode() == wx.WXK_RETURN:
			self.OnFindByTextChange( event, True )
		event.Skip()

	def OnFindByTextChange( self, event=None,FindNext= False ):
		if not FindNext: self.last_objects_found = []
		selected = self.findby_choice.GetSelection()
		search_text = self.find_text.GetValue()
		if len( search_text.strip() ) < 1:
			self.tree.UnselectAll()
			return
		# If we are looking for an ID, strip the id entered
		search_text = search_text.strip().replace("\\","\\\\")
		found_something = 0
		if selected == 0:
			prop = "id"
		else:
			prop = "name"
		object = None
		# Create the matcher text
		search_pattern = re.compile( "^%s" % search_text, re.I )
		for bin in self.binders:
			# Match the string in the binder property
			if re.search( search_pattern, bin[ prop ] ) is not None:
				if FindNext and ( bin in self.last_objects_found ):
					continue
				object = bin
				break
		# If we found nothing, clear the selection, otherwise, select it
		if object is None:
			self.tree.UnselectAll()
			self.last_objects_found = []
		else:
			self.tree.EnsureVisible( object.tree_item )
			self.tree.SelectItem( object.tree_item )
			self.last_objects_found.append( object )
		self.tree.Refresh()

	# The MENU BAR HANDLERS
	def OnBinderCreate( self, event ):
		bin = rex.binders.binder( self.account, None )
		# Create the new binder on the server, that will give it an ID
		dlg = wx.TextEntryDialog( self, "Please enter the name of the new binder",
										"New Binder",
										"Binder Name" )
		dlg.SetValue( 'New binder' )
		if dlg.ShowModal() != wx.ID_OK:
			var = None
			dlg.Destroy()
			return
		new_name = dlg.GetValue().lower()
		new_name = new_name.replace("[", "" )
		new_name = new_name.replace("]", "" )
		new_name = new_name.replace("#", "" )
		new_name = new_name.replace("$", "" )
		new_name = new_name.replace("'", "" )
		new_name = new_name.replace("\"", "" )
		new_name = new_name.replace(".", "_" )
		print "About to create binder:", new_name
		bin['name'] = new_name
		if not bin.create(): return
		self.binders.append( bin )
		# Create a tree node for the binder object and it's children
		bin_item = self.AppendBinder( bin )
		bin.tree_item = bin_item
		self.tree.SelectItem( bin_item )
		#self.OnBinderEdit( None )
		self.reload_binders(); 

	# The MENU BAR HANDLERS
	def OnBinderMirror( self, event ):
		item = self.tree.GetSelection()
		if item is None: return
		real_bin = self.tree.GetPyData( item )
		if real_bin is None: return
		if real_bin.object_name != "binder": return
		if ( real_bin["kind"] == "SYSTEM" ): return
		if ( real_bin.mirror ): return
		bin = rex.binders.binder( self.account, None )
		# Create the new binder on the server, that will give it an ID
		dlg = wx.TextEntryDialog( self, "Please enter the name of the new mirror binder",
										"New Mirror of %s" % real_bin['name'],
										"Binder Name" )
		dlg.SetValue( 'New mirror binder' )
		if dlg.ShowModal() != wx.ID_OK:
			var = None
			dlg.Destroy()
			return
		new_name = dlg.GetValue().lower()
		new_name = new_name.replace("[", "" )
		new_name = new_name.replace("]", "" )
		new_name = new_name.replace("#", "" )
		new_name = new_name.replace("$", "" )
		new_name = new_name.replace("'", "" )
		new_name = new_name.replace("\"", "" )
		new_name = new_name.replace(".", "_" )
		print "Baout to create binder:", new_name
		bin['name'] = new_name
		bin.mirror = True
		bin['mirror_id'] = real_bin['id']
		bin.original_name= real_bin['name']
		if not bin.create(): return
		self.binders.append( bin )
		# Create a tree node for the binder object and it's children
		bin_item = self.AppendBinder( bin )
		bin.tree_item = bin_item
		self.tree.SelectItem( bin_item )
		#self.OnBinderEdit( None )

	def OnBinderClone( self, event ):
		item = self.tree.GetSelection()
		if item is None: return
		bin = self.tree.GetPyData( item )
		if bin is None: return
		if bin.object_name != "binder": return
		if ( bin["kind"] == "SYSTEM" ): return
		if ( bin.mirror ): return
		# Create the new binder on the server, that will give it an ID
		new_bid = bin.clone()
		self.reload_binders()

	def OnBinderEdit( self, event ):
		item = self.tree.GetSelection()
		if item is None: return
		bin = self.tree.GetPyData( item )
		if bin is None: return
		if bin.object_name != "binder": return
		if ( bin["kind"] == "SYSTEM" ): return
		dlg = binders.BinderProps( self, bin )
		if dlg.ShowModal() != wx.ID_OK: return
		display  = dlg.GetValue().lower()
		bin.save()
		self.SetTextOfItem( item, display )
		self.ColorizeBinder( bin, item )
		#~ if bin.mirror:
			# Get rid of the variables and instances tree items if any
			#~ if bin.instances_tree_item is not None:
				#~ self.tree.Delete( bin.instances_tree_item )
				#~ bin.instances_tree_item = None
			#~ if bin.variables_tree_item is not None:
				#~ self.tree.Delete( bin.variables_tree_item )
				#~ bin.variables_tree_item = None
		#~ else:
			#~ if bin.variables_tree_item is None:
				#~ bin.variables_tree_item = self.tree.AppendItem( item, "Variables")
			#~ if bin.instances_tree_item is None:
				#~ bin.instances_tree_item = self.tree.AppendItem( item, "Instances")

	def OnBinderOpen( self, event ):
		item = self.tree.GetSelection()
		if item is None: return
		bin = self.tree.GetPyData( item )
		if bin is None: return
		if bin.object_name != "binder": return
		if bin["kind"] == "SYSTEM": return
		if bin.mirror: return
		if bin.editor is not None:
			self.account.window.bbook.SetSelection( common.get_page_index( self.account.window.bbook, bin.editor ) )
			return
		bin.editor = binders.instances_control( bin )
		self.account.window.bbook.AddPage( bin.editor, bin['id'] )
		pi = common.get_page_index( self.account.window.bbook, bin.editor )
		try:
			self.account.window.bbook.SetSelection( pi )
			self.account.window.bbook.SetPageImage( pi, self.account.window.icon_from_rex_object( bin ) )
		except:
			common.show_error("Failed to switch to editor", False)
		bin.editor.GetNext()


	def OnBinderDelete( self, event ):
		item = self.tree.GetSelection()
		if item is None: return
		bin = self.tree.GetPyData( item )
		if bin is None: return
		if bin.object_name != "binder": return
		if ( bin["kind"] == "SYSTEM" ): return
		# Confirm delete
		res = wx.MessageBox( "Are you sure you want to delete this binder and all it's instance?", "Confirm Delete", wx.YES_NO )
		if res != wx.YES: return
		if bin.delete():
			if bin.editor is not None:
				bin.editor.Destroy()
			for ins in bin.instances:
				if ins.editor is not None:
					ins.editor.Destroy()
			self.binders.remove( bin )
			self.tree.Delete( item )
			bin = None


	def OnBinderNewOptimization( self, event ):
		dlg = new_optimization( self, -1, "Create New Optimization", size=wx.Size(350,200), style=wx.DEFAULT_DIALOG_STYLE )

	def OnBinderNewVariable( self, event ):
		item = self.tree.GetSelection()
		if item is None: return
		bin = self.tree.GetPyData( item )
		if bin is None: return
		if bin.object_name != "binder": return
		if bin.mirror: return
		if ( bin["kind"] == "SYSTEM" ) and ( bin["name"] != "CONTACT" ): return
		var = rex.binders.variable( self.account, bin, None )
		dlg = wx.TextEntryDialog( self, "Please enter the name of the new variable",
										"Edit Variable",
										"Variable Name" )
		dlg.SetValue( '' )
		common.metalic( dlg )
		if dlg.ShowModal() != wx.ID_OK:
			var = None
			dlg.Destroy()
			return
		new_name = dlg.GetValue().lower()
		new_name = new_name.replace("[", "" )
		new_name = new_name.replace("]", "" )
		new_name = new_name.replace("#", "" )
		new_name = new_name.replace("$", "" )
		new_name = new_name.replace("'", "" )
		new_name = new_name.replace("\"", "" )
		new_name = new_name.replace(".", "_" )
		new_name = new_name.replace(" ", "_" )
		new_name = new_name.replace("\n", "_" )
		new_name = new_name.replace("\r", "_" )
		new_name = new_name.replace("\t", "_" )
		#~ full_name= var.binder['name'] + "." + new_name
		#~ if len( full_name.strip() ) > 32:
			#~ msg = "The full variable name \"%s\"\nexceeds the recommended length of " + \
				  #~ "no more than 32 characters.\n\nProceed any way?: "
			#~ msg = msg % full_name
			#~ # Confirm
			#~ dlg = wx.MessageDialog( self, msg, "Full Variable Name Too Long", wx.YES_NO )
			#~ icon = icon_manager.get_icon( "ESM" )
			#~ dlg.SetIcon( icon )
			#~ if dlg.ShowModal() != wx.ID_YES: return
		var['name'] = new_name
		var['type'] = "unlimited" # Set default type clientside to avoid long binder refresh
		if not var.create( new_name ): return
		bin.variables.append( var )
		bin.variables.sort()
		var_item = self.AppendVariable( bin.tree_item, var )
		var.tree_item = var_item
		self.tree.SelectItem( var_item )
		#self.OnVariableEdit( None )
		self.rebuild_mirrors( bin )
		#self.reload_binders(); # Too slow on large sites to reload with this 


	def OnBinderNewInstance( self, event ):
		''' This should be deleted or changed to open/search-for the binder window then create a new instance'''
		#print "OnBinderNewInstance"
		item = self.tree.GetSelection()
		if item is None: return
		bin = self.tree.GetPyData( item )
		if bin is None: return
		if bin.object_name != "binder": return
		if bin.mirror: return
		if ( bin["kind"] == "SYSTEM" ): return
		ins = rex.binders.instance( self.account, bin, None )
		dlg = wx.TextEntryDialog( self, "Please enter the name of the new instance",
										"Create Instance",
										"Instance Name" )
		dlg.SetValue( 'New instance' )
		if dlg.ShowModal() != wx.ID_OK:
			ins = None
			dlg.Destroy()
			return
		new_name = dlg.GetValue().lower()
		new_name = new_name.replace("[", "" )
		new_name = new_name.replace("]", "" )
		new_name = new_name.replace("#", "" )
		new_name = new_name.replace("$", "" )
		new_name = new_name.replace("'", "" )
		new_name = new_name.replace("\"", "" )
		new_name = new_name.replace(".", "_" )
		print "About to create instance:", new_name
		ins['instance_name'] = new_name
		if not ins.create(): return
		bin.instances.append( ins )
		ins_item = self.AppendInstance( bin.instances_tree_item, ins )
		ins.tree_item = ins_item
		self.tree.Expand( item )
		self.tree.SelectItem( ins_item )
		#self.OnInstanceEdit( None )
		self.rebuild_mirrors( bin )

	def OnInstancePreview( self, event ):
		pass

	def OnOptimizationDelete( self, event ):
		item = self.tree.GetSelection()
		if item is None: return
		opt = self.tree.GetPyData( item )
		if opt is None: return
		if opt.object_name != "optimization": return
		if ( opt.binder["kind"] == "SYSTEM" ) and ( opt.binder["name"] != "CONTACT" ): return
		# Confirm delete
		res = wx.MessageBox( "Are you sure you want to delete this optimization?", "Confirm Delete", wx.YES_NO )
		if res != wx.YES: return
		bin = opt.binder
		if opt.delete():
			self.tree.Delete( item )
			opt.binder.optimizations.remove( opt )
			opt = None

	def OnVariableCopy( self, event ):
		item = self.tree.GetSelection()
		if item is None: return
		var = self.tree.GetPyData( item )
		if var is None: return
		if var.object_name != "variable": return
		selected_var = "<#[%s.%s]#>" % (var.binder['name'], var['name'] )
		# Now let's put it in the clipboard
		clipdata = wx.TextDataObject()
		clipdata.SetText( selected_var )
		wx.TheClipboard.Open()
		wx.TheClipboard.SetData( clipdata )
		wx.TheClipboard.Close()

	def OnBinderCopy( self, event ):
		item = self.tree.GetSelection()
		if item is None: return
		obj = self.tree.GetPyData( item )
		if obj is None: return
		if obj.object_name != "binder": return
		bintag = "%s.%s" % ( obj["name"], obj["id"] )
		#bintag = "<#[BINDER_%s]#>" % ( obj["id"] )
		# Now let's put it in the clipboard
		clipdata = wx.TextDataObject()
		clipdata.SetText( bintag )
		wx.TheClipboard.Open()
		wx.TheClipboard.SetData( clipdata )
		wx.TheClipboard.Close()

	def OnVariableEdit( self, event ):
		item = self.tree.GetSelection()
		if item is None: return
		var = self.tree.GetPyData( item )
		if var is None: return	
		if var.object_name != "variable": return
		if ( var.binder["kind"] == "SYSTEM" ) and ( var.binder["name"] != "CONTACT" ): return
		
		dlg = var_edit( self, -1, "Edit Variable Properties", size=wx.Size(350,200), style=wx.DEFAULT_DIALOG_STYLE )
		dlg.nameText.SetValue( var['name'] )
		dlg.typeChoice.Select( dlg.typeList.index( var['type'] ) )
		dlg.CenterOnScreen()

		if dlg.ShowModal() != wx.ID_OK:
			var = None
			dlg.Destroy()
			return

		p = re.compile( "[\[\]#$'\"]" )
		q = re.compile( "[\. ]" )
		new_name  = p.sub( "", dlg.nameText.GetValue().lower() )
		new_name  = q.sub( "_", new_name )
		new_type  = dlg.typeChoice.GetStringSelection()
		full_name = var.binder['name'] + "." + new_name
		if len( full_name.strip() ) > 32:
			msg = "The full variable name \"%s\"\nexceeds the recommended length of " + \
				  "no more than 32 characters.\n\nProceed any way?: "
			msg = msg % full_name
			# Confirm
			dlg = wx.MessageDialog( self, msg, "Full Variable Name Too Long", wx.YES_NO )
			icon = icon_manager.get_icon( "ESM" )
			dlg.SetIcon( icon )
			if dlg.ShowModal() != wx.ID_YES: return

		# need to do an update?
		if var["name"] != new_name or var["type"] != new_type:
			# The save operation always needs var["name"] to be dirty
			var["name"] = var["name"]
			item_name   = var["name"]
			orig_type   = var["type"]
			# need to change the name?
			if var["name"].lower() != new_name:
				var["new_name"] = new_name
				item_name       = new_name
			# need to change the type?
			if var["type"] != new_type:
				var["type"] = new_type
			
			res = var.save()
			if res == False or res == '':
				dlg.typeChoice.Select( dlg.typeList.index( orig_type ) )
				var["type"] = orig_type
			else: 
				self.tree.SetItemText( var.tree_item, item_name, 1 )
				self.rebuild_mirrors( var.binder )
				var["name"] = item_name

			var.set_clean()

	def OnVariableDelete( self, event ):
		item = self.tree.GetSelection()
		if item is None: return
		var = self.tree.GetPyData( item )
		if var is None: return
		if var.object_name != "variable": return
		if ( var.binder["kind"] == "SYSTEM" ) and ( var.binder["name"] != "CONTACT" ): return
		# Confirm delete
		res = wx.MessageBox( "Are you sure you want to delete this variable and all it's values?", "Confirm Delete", wx.YES_NO )
		if res != wx.YES: return
		bin = var.binder
		if var.delete():
			self.tree.Delete( item )
			var.binder.variables.remove( var )
			var = None
			self.rebuild_mirrors( bin )

	def OnTreeRightClick( self, event ):
		item, where, col = self.tree.HitTest( event.GetPosition() )
		if item is None: return
		object = None
		try: object = self.tree.GetPyData( item )
		except: pass
		if object is None: return
		menu = None
		# Right clicked on a child node of a binder
		common.dprint("object selected: ", object.__class__ )
		if object.__class__ is wx._controls.TreeItemId:
			# Set it's menu, set the item to the binders item and get it's object
			inode  = item
			item   = self.tree.GetPyData( item )
			object = self.tree.GetPyData( item )
			# If this is a mirror binder, don't show anything
			try:
				if object.mirror:
					return
			except:
				pass
			if inode == object.tree_item:
				menu = self.var_node_menu
			#~ elif inode == object.instances_tree_item:
				#~ menu = self.ins_node_menu
		else:
			if type( object ) == str: 
				if(object == "Optimizations"):
					# Someone clicked on the "Optimizations" subtree, but not on
					# a specific optimization. Find the binder parent, and 
					# then use that for later logic instead.
					binderparent = self.tree.GetItemParent(item)
					try:
						item = self.tree.GetItemParent(item);
						if item is None: return
						object = self.tree.GetPyData(item)
					except:
						return					
				else:
					# Nothing to do then.
					return
					
			if object.object_name == "binder":
				menu = self.bin_menu
			elif object.object_name == "variable":
				menu = self.var_menu
			elif object.object_name == "optimization":
				menu = self.opt_menu
			#~ elif object.object_name == "instance":
				#~ menu = self.ins_menu
			#~ elif object.object_name == "instance_mirror":
				#~ menu = self.mirror_ins_menu

		if menu is None: return
		#self.tree.EnsureVisible( item )
		self.tree.SelectItem( item )
		self.PopupMenu( menu, wx.Point( event.m_x + 5, event.m_y + 15) )

	def OnItemDoubleClick( self, event ):
		#print "Item double clicked"
		item = self.tree.GetSelection()
		if item is None: return
		object = self.tree.GetPyData( item )
		if object is None: return
		if object.object_name == "binder":
			self.OnBinderOpen( event )
		elif object.object_name == "variable":
			self.OnVariableEdit( event )
		elif object.object_name == "instance":
			self.OnInstanceEdit( event )

	def SetTextOfItem( self, item, text ):
		self.tree.SetItemText( item, text )

	def CloseAllFrames( self ):
		'''Cycle through all binder instances and close off their frames if any.'''
		for b in self.binders:
			# Check it's child issue
			for i in b.instances:
				if i.editor is not None:
					f = i.editor
					if f.OnClose( None ):
						f.Destroy()
					else:
						return False
		return True
